/////////////////////////////////////////////////////////////////////////////
// This file is part of the "Java-DAP" project, a Java implementation
// of the OPeNDAP Data Access Protocol.
//
// Copyright (c) 2007 OPeNDAP, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
/////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections;
using System.IO;
using NDODS.DAP.BaseTypes;
using NDODS.DAP.Exceptions;
using NDODS.DAP.XMLParser;

namespace NDODS.DAP.Server
{
    /// <summary> Holds a OPeNDAP Server <code>Grid</code> value.
    /// 
    /// </summary>
    /// <author>  ndp
    /// </author>
    /// <version>  $Revision: 15901 $
    /// </version>
    /// <seealso cref="BaseType">
    /// </seealso>
    [Serializable]
    public abstract class SDGrid : DGrid, IServerArrayMethods, IRelOps
    {
        //UPGRADE_NOTE: Respective javadoc comments were merged.  It should be changed in order to comply with .NET documentation conventions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1199'"
        /// <summary> Get the value of the IsRead property.
        /// 
        /// </summary>
        /// <returns> <code>true</code> if the variable has been Read,
        /// <code>false</code> otherwise.
        /// </returns>
        /// <seealso cref="Read">
        /// </seealso>
        /// <summary> Set the IsRead property. A normal variable is Read using the
        /// <code>Read()</code> method. Once Read the <em>IsRead</em> property is
        /// <code>true</code>. Use this function to manually set the property
        /// value. By default this property is false.
        /// 
        /// </summary>
        /// <seealso cref="IsRead()">
        /// </seealso>
        /// <seealso cref="Read">
        /// </seealso>
        public virtual bool IsRead {
            get { return (ReadMe); }

            set { ReadMe = value; }
        }

        private bool Project;
        private bool Synthesized;
        private bool ReadMe;
        internal ArrayList AP;

        /// <summary> Constructs a new <code>SDGrid</code>.</summary>
        public SDGrid() : base() {
            Project = false;
            Synthesized = false;
            ReadMe = false;
        }

        /// <summary> Constructs a new <code>SDGrid</code> with name <code>n</code>.
        /// 
        /// </summary>
        /// <param name="n">the name of the variable.
        /// </param>
        public SDGrid(String n) : base(n) {
            Project = false;
            Synthesized = false;
            ReadMe = false;
        }


        /// <summary> When projected (using whatever the current constraint provides in the way
        /// of a projection) am I still a Grid?
        /// 
        /// </summary>
        /// <returns> True if projected grid is still a grid. False otherwise.
        /// </returns>
        public virtual bool projectionYieldsGrid() {
            // For each dimension in the Array part, check the corresponding Map
            // vector to make sure it is present in the projected Grid. If for each
            // projected dimension in the Array component, there is a matching Map
            // vector, then the Grid is valid.
            bool valid = true;

            // Don't bother checking if the Array component is not included.
            if (!((SDArray) arrayVar).isProject())
                return false;

            IEnumerator aDims = arrayVar.Dimensions;
            IEnumerator e = mapVars.GetEnumerator();

            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            while (valid && e.MoveNext() && aDims.MoveNext()) {
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                DArrayDimension thisDim = (DArrayDimension) aDims.Current;
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                SDArray mapArray = (SDArray) e.Current;
                DArrayDimension thisMap = mapArray.FirstDimension;

                if (thisDim.Size > 0) {
                    // System.out.println("Dimension Contains Data.");

                    if (mapArray.isProject()) {
                        // This map vector better be projected!
                        // System.out.println("Map Vector Projected, checking projection image...");

                        // Check the matching Map vector; the Map projection must equal
                        // the Array dimension projection

                        valid = thisMap.Start == thisDim.Start && thisMap.Stop == thisDim.Stop &&
                                thisMap.Stride == thisDim.Stride;
                    }
                    else {
                        // System.out.println("Map Vector not Projected.");
                        valid = false;
                    }
                }
                else {
                    // System.out.println("Dimension empty. Verifing cooresponding Map vector not projected...");
                    // Corresponding Map vector must be excluded from the
                    // projection or it's not a grid.
                    valid = !mapArray.isProject();
                }
            }

            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            if (e.MoveNext() != aDims.MoveNext())
                valid = false;

            return valid;
        }

        /// <summary> How many prohected components of this Grid object?
        /// 
        /// </summary>
        /// <returns> The number of projected components.
        /// </returns>
        public virtual int projectedComponents(bool constrained) {
            int comp;

            if (constrained) {
                comp = ((SDArray) arrayVar).isProject() ? 1 : 0;

                IEnumerator e = mapVars.GetEnumerator();

                //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                while (e.MoveNext()) {
                    //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                    if (((SDArray) e.Current).isProject())
                        comp++;
                }
            }
            else {
                comp = 1 + mapVars.Count;
            }

            return comp;
        }


        /// <summary> Write the variable's declaration in a C-style syntax. This
        /// function is used to create textual representation of the Data
        /// Descriptor Structure (DDS).  See <em>The OPeNDAP User Manual</em> for
        /// information about this structure.
        /// 
        /// </summary>
        /// <param name="os">        The <code>StreamWriter</code> on which to Print the
        /// declaration.
        /// </param>
        /// <param name="space">     Each line of the declaration will begin with the
        /// characters in this string.  Usually used for leading spaces.
        /// </param>
        /// <param name="print_semi">a bool value indicating whether to Print a
        /// semicolon at the end of the declaration.
        /// </param>
        /// <seealso cref="BaseType.PrintDeclaration(StreamWriter,string,bool)">
        /// </seealso>
        public override void PrintDeclaration(StreamWriter os, String space, bool print_semi, bool constrained) {
            // BEWARE! Since PrintDeclaration()is (multiple) overloaded in BaseType
            // and all of the different signatures of PrintDeclaration() in BaseType
            // lead to one signature, we must be careful to override that
            // SAME signature here. That way all calls to PrintDeclaration() for
            // this object lead to this implementation.


            bool isSingle = false;
            bool isStructure = false;
            bool isGrid = false;
            bool psemi = true;

            //os.println("The gird contains "+projectedComponents(true)+" projected components");

            if (constrained && projectedComponents(true) == 0)
                return;

            // If we are printing the declaration of a constrained Grid then check for
            // the case where the projection removes all but one component; the
            // resulting object is a simple array.

            if (constrained && projectedComponents(true) == 1) {
                //os.println("It's a single Array.");
                isSingle = true;
                psemi = print_semi;
            }
                // If there are M (< N) componets (Array and Maps combined) in a N
                // component Grid, send the M components as elements of a Struture.
                // This will preserve the grouping without violating the rules for a
                // Grid.
            else if (constrained && !projectionYieldsGrid()) {
                //os.println("It's a Structure.");
                isStructure = true;
            }
            else {
                // The number of elements in the (projected) Grid must be such that
                // we have a valid Grid object; send it as such.
                //os.println("It's a Grid.");
                isGrid = true;
            }

            if (isGrid) {
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                os.WriteLine(space + TypeName + " {");
            }
            if (isGrid) {
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                os.WriteLine(space + " ARRAY:");
            }

            if (isStructure) {
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                os.WriteLine(space + "Structure {");
            }

            ((SDArray) arrayVar).PrintDeclaration(os, space + (isSingle ? "" : "    "), psemi, constrained);

            if (isGrid) {
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                os.WriteLine(space + " MAPS:");
            }
            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            for (IEnumerator e = mapVars.GetEnumerator(); e.MoveNext();) {
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                SDArray sda = (SDArray) e.Current;
                sda.PrintDeclaration(os, space + (isSingle ? "" : "    "), psemi, constrained);
            }

            if (isStructure || isGrid) {
                os.Write(space + "} " + Name);
                if (print_semi) {
                    //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                    os.WriteLine(";");
                }
            }

            return;
        }


        /// <summary> Prints the value of the variable, with its declaration.  This
        /// function is primarily intended for debugging OPeNDAP applications and
        /// text-based clients such as geturl.
        /// <p/>
        /// <h2> Important Note</h2>
        /// This method overrides the BaseType method of the same name and
        /// type signature and it significantly changes the behavior for all versions
        /// of <code>PrintValue()</code> for this type:
        /// <b><i> All the various versions of printVal() will only
        /// Print a value, or a value with declaration, if the variable is
        /// in the projection.</i></b>
        /// <br>
        /// <br>In other words, if a call to
        /// <code>isProject()</code> for a particular variable returns
        /// <code>true</code> then <code>printVal()</code> will Print a value
        /// (or a declaration and a value).
        /// <br>
        /// <br>If <code>isProject()</code> for a particular variable returns
        /// <code>false</code> then <code>printVal()</code> is basically a No-Op.
        /// <br>
        /// <br>
        /// 
        /// </summary>
        /// <param name="os">          the <code>StreamWriter</code> on which to Print the value.
        /// </param>
        /// <param name="space">       this value is passed to the <code>PrintDeclaration</code> method,
        /// and controls the leading spaces of the output.
        /// </param>
        /// <param name="Print_decl_p">a bool value controlling whether the
        /// variable declaration is printed as well as the value.
        /// </param>
        /// <seealso cref="BaseType.PrintValue(StreamWriter,string,bool)">
        /// </seealso>
        /// <seealso cref="ServerMethods.isProject()">
        /// </seealso>
        public override void PrintValue(StreamWriter os, String space, bool print_decl_p) {
            if (!isProject())
                return;

            //System.out.println("\nSome Part of this object is projected...");

            if (print_decl_p) {
                PrintDeclaration(os, space, false, true);
                os.Write(" = ");
            }

            bool isStillGrid = projectionYieldsGrid();

            os.Write("{ ");
            if (isStillGrid)
                os.Write("ARRAY: ");

            if (((SDArray) arrayVar).isProject())
                arrayVar.PrintValue(os, "", false);

            if (isStillGrid)
                os.Write(" MAPS: ");

            bool firstPass = true;
            IEnumerator e = mapVars.GetEnumerator();
            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            while (e.MoveNext()) {
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                SDArray sda = (SDArray) e.Current;

                if (((SDArray) sda).isProject()) {
                    if (!firstPass)
                        os.Write(", ");
                    sda.PrintValue(os, "", false);
                    firstPass = false;
                }
            }
            os.Write(" }");

            if (print_decl_p) {
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                os.WriteLine(";");
            }
        }


        /// <summary> Adds a variable to the container. This overrides the same method in
        /// the parent class <code>DGrid</code> in order to add array projection
        /// functionality.
        /// 
        /// </summary>
        /// <param name="v">   the variable to add.
        /// </param>
        /// <param name="part">the part of the <code>DGrid</code> to be modified.  Allowed
        /// values are <code>ARRAY</code> or <code>MAPS</code>.
        /// </param>
        /// <throws>  IllegalArgumentException if an invalid part was given. </throws>
        public override void addVariable(BaseType v, int part) {
            base.addVariable(v, part);
        }

        // --------------- Projection Interface

        /// <summary> Set the state of this variable's projection. <code>true</code> means
        /// that this variable is part of the current projection as defined by
        /// the current constraint expression, otherwise the current projection
        /// for this variable should be <code>false</code>.
        /// 
        /// </summary>
        /// <param name="state"><code>true</code> if the variable is part of the current
        /// projection, <code>false</code> otherwise.
        /// </param>
        /// <param name="all">  If <code>true</code>, set the Project property of all the
        /// members (and their children, and so on).
        /// </param>
        /// <seealso cref="CEEvaluator">
        /// </seealso>
        public virtual void setProject(bool state, bool all) {
            Project = state;
            if (all) {
                // System.out.println("SDGrid:setProject: Blindly setting Project");
                ((SDArray) arrayVar).setProject(state);

                //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                for (IEnumerator e = mapVars.GetEnumerator(); e.MoveNext();) {
                    //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                    IServerMethods sm = (IServerMethods) e.Current;
                    sm.setProject(state);
                }
            }
        }

        /// <summary> Set the state of this variable's projection. <code>true</code> means
        /// that this variable is part of the current projection as defined by
        /// the current constraint expression, otherwise the current projection
        /// for this variable should be <code>false</code>. <p>
        /// This is equivalent to setProjection(<code>state</code>,
        /// <code>true</code>).
        /// 
        /// </summary>
        /// <param name="state"><code>true</code> if the variable is part of the current
        /// projection, <code>false</code> otherwise.
        /// </param>
        /// <seealso cref="CEEvaluator">
        /// </seealso>
        public virtual void setProject(bool state) {
            setProject(state, true);
        }

        /// <summary> Check the projection state of this variable.
        /// Is the given variable marked as projected? If the variable is listed
        /// in the projection part of a constraint expression, then the CE parser
        /// should mark it as <em>projected</em>. When this method is called on
        /// such a variable it should return <code>true</code>, otherwise it
        /// should return <code>false</code>.
        /// 
        /// </summary>
        /// <returns> <code>true</code> if the variable is part of the current
        /// projections, <code>false</code> otherwise.
        /// </returns>
        /// <seealso cref="CEEvaluator">
        /// </seealso>
        /// <seealso cref="setProject(bool)">
        /// </seealso>
        /// <seealso cref="setProjection(int,int,int,int)">
        /// </seealso>
        public virtual bool isProject() {
            return (Project);
        }

        // --------------- RelOps Interface

        /// <summary> The RelOps interface defines how each type responds to relational
        /// operators. Most (all?) types will not have sensible responses to all of
        /// the relational operators (e.g. DGrid won't know how to match a regular
        /// expression but DString will). For those operators that are nonsensical a
        /// class should throw InvalidOperatorException.
        /// </summary>
        public virtual bool equal(BaseType bt) {
            throw new InvalidOperatorException("Equals (=) operator does not work with the type SDGrid!");
        }

        public virtual bool not_equal(BaseType bt) {
            throw new InvalidOperatorException("Not Equals (!=) operator does not work with the type SDGrid!");
        }

        public virtual bool greater(BaseType bt) {
            throw new InvalidOperatorException("Greater Than (>)operator does not work with the type SDGrid!");
        }

        public virtual bool greater_eql(BaseType bt) {
            throw new InvalidOperatorException("GreaterThan or equals (<=) operator does not work with the type SDGrid!");
        }

        public virtual bool less(BaseType bt) {
            throw new InvalidOperatorException("LessThan (<) operator does not work with the type SDGrid!");
        }

        public virtual bool less_eql(BaseType bt) {
            throw new InvalidOperatorException("LessThan oe equals (<=) operator does not work with the type SDGrid!");
        }

        public virtual bool regexp(BaseType bt) {
            throw new InvalidOperatorException("Regular Expression's don't work with the type SDGrid!");
        }

        // --------------- FileIO Interface

        /// <summary> Set the Synthesized property.
        /// 
        /// </summary>
        /// <param name="state">If <code>true</code> then the variable is considered a
        /// synthetic variable and no part of OPeNDAP will ever try to Read it from a
        /// file, otherwise if <code>false</code> the variable is considered a
        /// normal variable whose value should be Read using the
        /// <code>Read()</code> method. By default this property is false.
        /// </param>
        /// <seealso cref="IsSynthesized">
        /// </seealso>
        /// <seealso cref="Read">
        /// </seealso>
        public virtual void setSynthesized(bool state) {
            Synthesized = state;
        }

        /// <summary> Get the value of the Synthesized property.
        /// 
        /// </summary>
        /// <returns> <code>true</code> if this is a synthetic variable,
        /// <code>false</code> otherwise.
        /// </returns>
        public virtual bool IsSynthesized() {
            return (Synthesized);
        }

        /// <summary> IsRead a value from the named dataset for this variable.
        /// 
        /// </summary>
        /// <param name="datasetName">String identifying the file or other data store
        /// from which to Read a vaue for this variable.
        /// </param>
        /// <param name="specialO">   This <code>Object</code> is a goody that is used by Server implementations
        /// to deliver important, and as yet unknown, stuff to the Read method. If you
        /// don't need it, make it a <code>null</code>.
        /// </param>
        /// <returns> <code>true</code> if more data remains to be Read, otherwise
        /// <code>false</code>. This is an abtsract method that must be implemented
        /// as part of the installation/localization of a OPeNDAP server.
        /// </returns>
        /// <throws>  IOException </throws>
        /// <throws>  EOFException </throws>
        public abstract bool Read(String datasetName, Object specialO);


        /// <summary> Server-side serialization for OPeNDAP variables (sub-classes of
        /// <code>BaseType</code>).
        /// This does not send the entire class as the Java <code>Serializable</code>
        /// interface does, rather it sends only the binary data values. Other software
        /// is responsible for sending variable type information (see <code>DDS</code>).
        /// <p/>
        /// Writes data to a <code>DataOutputStream</code>. This method is used
        /// on the server side of the OPeNDAP client/server connection, and possibly
        /// by GUI clients which need to download OPeNDAP data, manipulate it, and
        /// then re-save it as a binary file.
        /// 
        /// </summary>
        /// <param name="sink">a <code>DataOutputStream</code> to write to.
        /// </param>
        /// <throws>  IOException thrown on any <code>OutputStream</code> exception. </throws>
        /// <seealso cref="BaseType">
        /// </seealso>
        /// <seealso cref="DDS">
        /// </seealso>
        /// <seealso cref="ServerDDS">
        /// </seealso>
        //UPGRADE_TODO: Class 'java.io.DataOutputStream' was converted to 'System.IO.BinaryWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataOutputStream'"
        public virtual void serialize(String dataset, BinaryWriter sink, CEEvaluator ce, Object specialO) {
            if (!IsRead)
                Read(dataset, specialO);

            if (ce.evalClauses(specialO)) {
                if (((IServerMethods) arrayVar).isProject())
                    ((IServerMethods) arrayVar).serialize(dataset, sink, ce, specialO);

                //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                for (IEnumerator e = mapVars.GetEnumerator(); e.MoveNext();) {
                    //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                    IServerMethods sm = (IServerMethods) e.Current;
                    if (sm.isProject())
                        sm.serialize(dataset, sink, ce, specialO);
                }
            }
        }

        //---------------------------------------------------------------------------------
        //------------------------- Array Projection Interface ----------------------------
        //..................................................................................

        /// <summary> Set the projection information for this dimension. The internal <code>DArray</code> is
        /// retrieved and then the <code>DArrayDimension</code>
        /// associated with the <code>dimension</code> specified is retrieved and the <code>start</code>
        /// <code>stride</code> and <code>stop</code> parameters are passed to its
        /// <code>setProjection()</code> method.
        /// 
        /// </summary>
        /// <param name="dimension">The dimension that is to be modified.
        /// </param>
        /// <param name="start">    The starting point for the projection of this <code>DArrayDimension</code>.
        /// </param>
        /// <param name="stride">   The size of the stride for the projection of this <code>DArrayDimension</code>.
        /// </param>
        /// <param name="stop">     The stopping point for the projection of this <code>DArrayDimension</code>.
        /// </param>
        /// <seealso cref="DArray">
        /// </seealso>
        /// <seealso cref="DArrayDimension">
        /// </seealso>
        public virtual void setProjection(int dimension, int start, int stride, int stop) {
            try {
                DArray a = (DArray) getVar(0);
                DArrayDimension d = a.getDimension(dimension);
                d.setProjection(start, stride, stop);

                DArray map = (DArray) getVar(dimension + 1);
                DArrayDimension mapD = map.getDimension(0);
                mapD.setProjection(start, stride, stop);
            }
            catch (NoSuchVariableException e) {
                //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
                throw new InvalidParameterException("SDGrid.setProjection(): Bad Value for dimension!: " + e.Message);
            }
        }


        /// <summary> Gets the <b>start</b> value for the projection of the
        /// <code>dimension</code> indicated. The parameter
        /// <code>dimension</code> is checked against the instance of the
        /// <code>SDArray</code> for bounds violation.
        /// 
        /// </summary>
        /// <param name="dimension">The dimension from whose projection to retrieve the
        /// <code>start</code> value.
        /// </param>
        public virtual int getStart(int dimension) {
            try {
                DArray a = (DArray) getVar(0);
                DArrayDimension d = a.getDimension(dimension);
                return (d.Start);
            }
            catch (NoSuchVariableException e) {
                //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
                throw new InvalidParameterException("SDGrid.getStart(): Bad Value for dimension!: " + e.Message);
            }
        }


        /// <summary> Gets the <b>stride</b> value for the projection of the
        /// <code>dimension</code> indicated. The parameter
        /// <code>dimension</code> is checked against the instance of the
        /// <code>SDArray</code> for bounds violation.
        /// 
        /// </summary>
        /// <param name="dimension">The dimension from whose projection to retrieve the
        /// <code>stride</code> value.
        /// </param>
        public virtual int getStride(int dimension) {
            try {
                DArray a = (DArray) getVar(0);
                DArrayDimension d = a.getDimension(dimension);
                return (d.Stride);
            }
            catch (NoSuchVariableException e) {
                //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
                throw new InvalidParameterException("SDGrid.getStride(): Bad Value for dimension!: " + e.Message);
            }
        }


        /// <summary> Gets the <b>stop</b> value for the projection of the
        /// <code>dimension</code> indicated. The parameter
        /// <code>dimension</code> is checked against the instance of the
        /// <code>SDArray</code> for bounds violation.
        /// 
        /// </summary>
        /// <param name="dimension">The dimension from whose projection to retrieve the
        /// <code>stop</code> value.
        /// </param>
        public virtual int getStop(int dimension) {
            try {
                DArray a = (DArray) getVar(0);
                DArrayDimension d = a.getDimension(dimension);
                return (d.Stop);
            }
            catch (NoSuchVariableException e) {
                //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
                throw new InvalidParameterException("SDGrid.getStop(): Bad Value for dimension!: " + e.Message);
            }
        }


        /// <summary> Write the variable's declaration in a C-style syntax. This
        /// function is used to create textual representation of the Data
        /// Descriptor Structure (DDS).  See <em>The OPeNDAP User Manual</em> for
        /// information about this structure.
        /// 
        /// </summary>
        /// <seealso cref="BaseType.PrintDeclaration(StreamWriter,string,bool)">
        /// </seealso>
        /// <opendap.ddx.experimental>  </opendap.ddx.experimental>
        public override void PrintXML(StreamWriter pw, String pad, bool constrained) {
            // BEWARE! Since PrintDeclaration()is (multiple) overloaded in BaseType
            // and all of the different signatures of PrintDeclaration() in BaseType
            // lead to one signature, we must be careful to override that
            // SAME signature here. That way all calls to PrintDeclaration() for
            // this object lead to this implementation.


            bool isSingle = false;
            bool isStructure = false;
            bool isGrid = false;
            bool psemi = true;

            //os.println("The gird contains "+projectedComponents(true)+" projected components");

            if (constrained && projectedComponents(true) == 0)
                return;

            // If we are printing the declaration of a constrained Grid then check for
            // the case where the projection removes all but one component; the
            // resulting object is a simple array.

            if (constrained && projectedComponents(true) == 1) {
                //os.println("It's a single Array.");
                isSingle = true;
            }
                // If there are M (< N) componets (Array and Maps combined) in a N
                // component Grid, send the M components as elements of a Struture.
                // This will preserve the grouping without violating the rules for a
                // Grid.
            else if (constrained && !projectionYieldsGrid()) {
                //os.println("It's a Structure.");
                isStructure = true;
            }
            else {
                // The number of elements in the (projected) Grid must be such that
                // we have a valid Grid object; send it as such.
                //os.println("It's a Grid.");
                isGrid = true;
            }

            if (isGrid) {
                pw.Write(pad + "<Grid ");
                if (Name != null) {
                    pw.Write(" name=\"" + DDSXMLParser.normalizeToXML(Name) + "\"");
                }
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                pw.WriteLine(">");
            }

            if (isStructure) {
                pw.Write(pad + "<Structure");
                if (Name != null) {
                    pw.Write(" name=\"" + DDSXMLParser.normalizeToXML(Name) + "\"");
                }
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                pw.WriteLine(">");
            }

            IEnumerator e = AttributeNames.GetEnumerator();

            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            while (e.MoveNext()) {
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                String aName = (String) e.Current;

                try {
                    Attribute a = GetAttribute(aName);
                    a.printXML(pw, pad + "\t", constrained);
                }
                catch (NoSuchAttributeException nsae) {}
            }

            (arrayVar).PrintXML(pw, pad + (isSingle ? "" : "\t"), constrained);

            if (isGrid) {
                e = mapVars.GetEnumerator();
                //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                while (e.MoveNext()) {
                    //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                    SDArray map = (SDArray) e.Current;
                    map.printAsMapXML(pw, pad + (isSingle ? "" : "\t"), constrained);
                }
            }
            else {
                e = mapVars.GetEnumerator();
                //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                while (e.MoveNext()) {
                    //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                    SDArray sda = (SDArray) e.Current;
                    sda.PrintXML(pw, pad + (isSingle ? "" : "\t"), constrained);
                }
            }


            if (isStructure) {
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                pw.WriteLine(pad + "</Structure>");
            }
            else if (isGrid) {
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                pw.WriteLine(pad + "</Grid>");
            }

            return;
        }

        /*
		
		if(isGrid){
		
		
		os.println(space + getTypeName() + " {" );
		os.println(space + " ARRAY:");
		
		((SDArray)arrayVar).PrintDeclaration(os, space + (isSingle ? "":"    ") , psemi, constrained);
		
		os.println(space + " MAPS:");
		
		for(Enumeration e = mapVars.elements(); e.hasMoreElements(); ) {
		SDArray sda = (SDArray)e.nextElement();
		sda.PrintDeclaration(os, space + (isSingle ? "":"    ") , psemi, constrained);
		}
		
		os.Print(space + "} " + getName());
		os.println(";");
		
		}
		
		if(isStructure){
		
		os.println(space + "Structure {");
		((SDArray)arrayVar).PrintDeclaration(os, space + (isSingle ? "":"    ") , psemi, constrained);
		
		
		for(Enumeration e = mapVars.elements(); e.hasMoreElements(); ) {
		SDArray sda = (SDArray)e.nextElement();
		sda.PrintDeclaration(os, space + (isSingle ? "":"    ") , psemi, constrained);
		}
		
		os.Print(space + "} " + getName());
		os.println(";");
		
		}
		
		if(isSingle){
		
		
		((SDArray)arrayVar).PrintDeclaration(os, space + (isSingle ? "":"    ") , psemi, constrained);
		
		for(Enumeration e = mapVars.elements(); e.hasMoreElements(); ) {
		SDArray sda = (SDArray)e.nextElement();
		sda.PrintDeclaration(os, space , psemi, constrained);
		}
		
		}
		*/
    }
}